import { Logger } from './logger';
import { IDebuggerConfig } from './debugConfig';
import { promises as fsPromises } from 'fs';
import { Source } from '@vscode/debugadapter';
import path from 'path';

interface IBreakpoint {
    id: number;
    source: Source;
    line: number;
    column?: number;
    condition?: string;
    hitCondition?: string;
    logMessage?: string;
    enabled: boolean;
    verified: boolean;
    hitCount: number;
}

interface IFunctionBreakpoint {
    id: number;
    functionName: string;
    condition?: string;
    hitCondition?: string;
    enabled: boolean;
    hitCount: number;
}

export class BreakpointManager {
    private logger: Logger;
    private config: IDebuggerConfig;
    private breakpoints: Map<string, IBreakpoint[]>;
    private functionBreakpoints: Map<string, IFunctionBreakpoint>;
    private nextBreakpointId: number;

    constructor(config: IDebuggerConfig) {
        this.config = config;
        this.logger = Logger.getInstance();
        this.breakpoints = new Map();
        this.functionBreakpoints = new Map();
        this.nextBreakpointId = 1;
    }

    public addBreakpoint(breakpoint: Omit<IBreakpoint, 'id' | 'hitCount'>): IBreakpoint {
        const id = this.nextBreakpointId++;
        const newBreakpoint: IBreakpoint = {
            ...breakpoint,
            id,
            hitCount: 0,
            source: new Source(
                path.basename(breakpoint.source.path || ''),
                breakpoint.source.path || '',
                undefined, // sourceReference
                undefined, // presentationHint
                'normal' // origin
            )
        };

        const sourcePath = newBreakpoint.source.path;
        if (!sourcePath) {
            throw new Error('断点源文件路径不能为空');
        }

        const sourceBreakpoints = this.breakpoints.get(sourcePath) || [];
        sourceBreakpoints.push(newBreakpoint);
        this.breakpoints.set(sourcePath, sourceBreakpoints);

        this.logger.debug(`添加断点: ${JSON.stringify(newBreakpoint)}`);
        return newBreakpoint;
    }

    public async addFunctionBreakpoint(functionName: string, condition?: string, hitCondition?: string): Promise<IFunctionBreakpoint> {
        try {
            // 解析函数名
            const { className, methodName } = this.parseFunctionName(functionName);

            // 构建函数断点命令
            let command = 'break-insert -f ';
            if (className) {
                command += `${className}.${methodName}`;
            } else {
                command += methodName;
            }

            // 添加条件（如果有）
            if (condition) {
                command += ` -c "${condition}"`;
            }

            // 发送命令到调试器
            const result = await this.sendDebuggerCommand(command);
            if (result.includes('error')) {
                throw new Error(`设置函数断点失败: ${result}`);
            }

            // 创建函数断点对象
            const breakpoint: IFunctionBreakpoint = {
                id: this.nextBreakpointId++,
                functionName,
                enabled: true,
                condition,
                hitCondition,
                hitCount: 0
            };

            this.functionBreakpoints.set(functionName, breakpoint);
            this.logger.debug(`添加函数断点: ${JSON.stringify(breakpoint)}`);

            return breakpoint;
        } catch (error) {
            this.logger.error(`添加函数断点失败: ${error}`);
            throw error;
        }
    }

    private parseFunctionName(functionName: string): { className?: string; methodName: string } {
        // 支持以下格式：
        // 1. MethodName
        // 2. ClassName.MethodName
        // 3. Namespace.ClassName.MethodName
        const parts = functionName.split('.');
        if (parts.length === 1) {
            return { methodName: parts[0] };
        }
        return {
            className: parts.slice(0, -1).join('.'),
            methodName: parts[parts.length - 1]
        };
    }

    public async updateFunctionBreakpoint(
        functionName: string,
        updates: {
            enabled?: boolean;
            condition?: string;
            hitCondition?: string;
        }
    ): Promise<void> {
        const breakpoint = this.functionBreakpoints.get(functionName);
        if (!breakpoint) {
            throw new Error(`函数断点未找到: ${functionName}`);
        }

        try {
            // 更新启用状态
            if (updates.enabled !== undefined && updates.enabled !== breakpoint.enabled) {
                const command = updates.enabled ? 'break-enable' : 'break-disable';
                await this.sendDebuggerCommand(`${command} ${breakpoint.id}`);
                breakpoint.enabled = updates.enabled;
            }

            // 更新条件
            if (updates.condition !== undefined && updates.condition !== breakpoint.condition) {
                if (updates.condition) {
                    await this.sendDebuggerCommand(`break-condition ${breakpoint.id} ${updates.condition}`);
                } else {
                    await this.sendDebuggerCommand(`break-condition ${breakpoint.id}`);
                }
                breakpoint.condition = updates.condition;
            }

            // 更新命中条件
            if (updates.hitCondition !== undefined) {
                breakpoint.hitCondition = updates.hitCondition;
            }

            this.logger.debug(`更新函数断点: ${JSON.stringify(breakpoint)}`);
        } catch (error) {
            this.logger.error(`更新函数断点失败: ${error}`);
            throw error;
        }
    }

    private async sendDebuggerCommand(command: string): Promise<string> {
        // TODO: 实现与调试器的通信
        // 这里需要通过调试会话发送命令到调试器
        return Promise.resolve(command);
    }

    public removeBreakpoint(source: string, line: number): void {
        const sourceBreakpoints = this.breakpoints.get(source);
        if (sourceBreakpoints) {
            if (line === -1) {
                // 删除所有断点
                this.breakpoints.delete(source);
                this.logger.debug(`移除文件的所有断点: ${source}`);
            } else {
                // 删除特定行的断点
                const index = sourceBreakpoints.findIndex(bp => bp.line === line);
                if (index !== -1) {
                    sourceBreakpoints.splice(index, 1);
                    this.logger.debug(`移除断点: ${source}:${line}`);
                }
            }
        }
    }

    public removeFunctionBreakpoint(functionName: string): void {
        this.functionBreakpoints.delete(functionName);
        this.logger.debug(`移除函数断点: ${functionName}`);
    }

    public getBreakpoints(source: string): IBreakpoint[] {
        return this.breakpoints.get(source) || [];
    }

    public getAllBreakpoints(): IBreakpoint[] {
        const allBreakpoints: IBreakpoint[] = [];
        for (const sourceBreakpoints of this.breakpoints.values()) {
            allBreakpoints.push(...sourceBreakpoints);
        }
        return allBreakpoints;
    }

    public getFunctionBreakpoints(): IFunctionBreakpoint[] {
        return Array.from(this.functionBreakpoints.values());
    }

    public async shouldBreak(source: string, line: number, variables: Map<string, any>): Promise<boolean> {
        const sourceBreakpoints = this.breakpoints.get(source);
        if (!sourceBreakpoints) {
            return false;
        }

        const breakpoint = sourceBreakpoints.find(bp => bp.line === line);
        if (!breakpoint || !breakpoint.enabled || !breakpoint.verified) {
            return false;
        }

        // 增加命中计数
        breakpoint.hitCount++;

        // 检查命中条件
        if (breakpoint.hitCondition) {
            try {
                const result = await this.evaluateHitCondition(breakpoint.hitCondition, breakpoint.hitCount);
                if (!result) {
                    return false;
                }
            } catch (error) {
                this.logger.error(`评估命中条件失败: ${error}`);
                return false;
            }
        }

        // 检查条件表达式
        if (breakpoint.condition) {
            try {
                return await this.evaluateCondition(breakpoint.condition, variables);
            } catch (error) {
                this.logger.error(`评估条件表达式失败: ${error}`);
                return false;
            }
        }

        return true;
    }

    public async shouldBreakOnFunction(functionName: string, variables: Map<string, any>): Promise<boolean> {
        const breakpoint = this.functionBreakpoints.get(functionName);
        if (!breakpoint || !breakpoint.enabled) {
            return false;
        }

        // 增加命中计数
        breakpoint.hitCount++;

        // 检查命中条件
        if (breakpoint.hitCondition) {
            try {
                const result = await this.evaluateHitCondition(breakpoint.hitCondition, breakpoint.hitCount);
                if (!result) {
                    return false;
                }
            } catch (error) {
                this.logger.error(`评估命中条件失败: ${error}`);
                return false;
            }
        }

        // 检查条件表达式
        if (breakpoint.condition) {
            try {
                return await this.evaluateCondition(breakpoint.condition, variables);
            } catch (error) {
                this.logger.error(`评估条件表达式失败: ${error}`);
                return false;
            }
        }

        return true;
    }

    public incrementHitCount(breakpointId: number): void {
        // 在所有断点中查找指定ID的断点
        for (const sourceBreakpoints of this.breakpoints.values()) {
            const breakpoint = sourceBreakpoints.find(bp => bp.id === breakpointId);
            if (breakpoint) {
                breakpoint.hitCount++;
                this.logger.debug(`增加断点命中计数: ${breakpointId}, 当前计数: ${breakpoint.hitCount}`);
                return;
            }
        }

        // 在函数断点中查找
        for (const functionBreakpoint of this.functionBreakpoints.values()) {
            if (functionBreakpoint.id === breakpointId) {
                functionBreakpoint.hitCount++;
                this.logger.debug(`增加函数断点命中计数: ${breakpointId}, 当前计数: ${functionBreakpoint.hitCount}`);
                return;
            }
        }

        this.logger.warn(`未找到断点ID: ${breakpointId}`);
    }

    public verifyBreakpoint(breakpointId: number): void {
        // 在所有断点中查找指定ID的断点并验证
        for (const sourceBreakpoints of this.breakpoints.values()) {
            const breakpoint = sourceBreakpoints.find(bp => bp.id === breakpointId);
            if (breakpoint) {
                breakpoint.verified = true;
                this.logger.debug(`验证断点: ${breakpointId}`);
                return;
            }
        }

        this.logger.warn(`未找到断点ID: ${breakpointId}`);
    }

    private async evaluateHitCondition(hitCondition: string, hitCount: number): Promise<boolean> {
        try {
            const match = hitCondition.match(/^([><%]=?|==)\s*(\d+)$/);
            if (!match) {
                this.logger.error(`无效的命中条件格式: ${hitCondition}`);
                return false;
            }

            const [, operator, countStr] = match;
            const targetCount = parseInt(countStr, 10);

            switch (operator) {
                case '>':
                    return hitCount > targetCount;
                case '>=':
                    return hitCount >= targetCount;
                case '<':
                    return hitCount < targetCount;
                case '<=':
                    return hitCount <= targetCount;
                case '==':
                    return hitCount === targetCount;
                case '%':
                    return hitCount % targetCount === 0;
                default:
                    this.logger.error(`不支持的命中条件运算符: ${operator}`);
                    return false;
            }
        } catch (error) {
            this.logger.error(`评估命中条件失败: ${error}`);
            return false;
        }
    }

    private async evaluateCondition(condition: string, variables: Map<string, any>): Promise<boolean> {
        try {
            const context = Object.create(null);
            for (const [key, value] of variables.entries()) {
                context[key] = value;
            }

            const evaluator = new Function(...Object.keys(context), `return ${condition};`);
            const result = evaluator(...Object.values(context));
            return Boolean(result);
        } catch (error) {
            this.logger.error(`评估条件表达式失败: ${error}`);
            return false;
        }
    }

    private async handleLogPoint(breakpoint: IBreakpoint, variables: Map<string, any>): Promise<void> {
        try {
            if (!breakpoint.logMessage) {
                return;
            }

            // 解析日志消息中的变量引用
            const message = breakpoint.logMessage.replace(/\{([^}]+)\}/g, (match, expr) => {
                try {
                    // 处理嵌套属性访问 (例如: obj.prop.value)
                    const parts = expr.split('.');
                    let value = variables.get(parts[0]);

                    // 遍历属性路径
                    for (let i = 1; i < parts.length && value != null; i++) {
                        value = value[parts[i]];
                    }

                    // 格式化值
                    if (value === null) {
                        return 'null';
                    } else if (value === undefined) {
                        return 'undefined';
                    } else if (typeof value === 'object') {
                        return JSON.stringify(value);
                    } else {
                        return String(value);
                    }
                } catch (error) {
                    this.logger.error(`解析日志消息变量失败: ${error}`);
                    return `{${expr}:error}`;
                }
            });

            // 构建日志条目
            const logEntry = {
                timestamp: new Date().toISOString(),
                source: breakpoint.source.path,
                line: breakpoint.line,
                message: message
            };

            // 记录日志
            this.logger.info(JSON.stringify(logEntry));

            // 如果配置了日志文件，也写入文件
            if (this.config.logFile) {
                await this.appendToLogFile(logEntry);
            }
        } catch (error) {
            this.logger.error(`处理日志点失败: ${error}`);
        }
    }

    private async appendToLogFile(logEntry: { timestamp: string; source: string; line: number; message: string }): Promise<void> {
        try {
            if (!this.config.logFile) {
                return;
            }
            const logLine = `[${logEntry.timestamp}] ${logEntry.source}:${logEntry.line} - ${logEntry.message}\n`;
            await fsPromises.appendFile(this.config.logFile, logLine);
        } catch (error) {
            this.logger.error(`写入日志文件失败: ${error}`);
        }
    }

    public dispose(): void {
        this.breakpoints.clear();
        this.functionBreakpoints.clear();
    }
} 